#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<pthread.h>

#define _PORT_ 8080
#define _BACKLG_ 5
#define LINE_MAX 1024

void startup(int sock) {
    printf("%d\n", sock);
    struct sockaddr_in server_socket;

    //填写sockaddr_in结构
    bzero(&server_socket, sizeof(server_socket));
    server_socket.sin_family = AF_INET;
    server_socket.sin_addr.s_addr = htonl(INADDR_ANY);
    server_socket.sin_port = htons(_PORT_);

    int opt = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    if(bind(sock, (struct sockaddr*)&server_socket, sizeof(struct sockaddr_in)) < 0) {
        perror("bind");
        close(sock);
    }

    if(listen(sock, _BACKLG_) < 0) {
        perror("listen");
        close(sock);
    }
}

void getlin(int sock, char line[]) {
    int i = 0;
    int c = 0;
    while(i<LINE_MAX-1 && c != '\n') {
        recv(sock, &c, 1, 0);
        if(c == '\r') {
                recv(sock, &c, 1, 0);
        }

        line[i++] = c;
    }
    line[i] = '\0';
}

void* server(void* arg) {
    int sock =  *(int*) arg; //sock为客户端套接字
    char line[LINE_MAX] = {0};

    //创建socket文件描述符
    int nm_sock = socket(AF_INET, SOCK_STREAM, 0);
    //填写 NodeMUC的ip和端口号
    struct sockaddr_in nm_addr;
    memset(&nm_addr, 0, sizeof(nm_addr));
    nm_addr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &nm_addr.sin_addr); //TODO
    nm_addr.sin_port = htons(atoi("9999"));
    //connect链接
    int ret = connect(nm_sock, (struct sockaddr*)&nm_addr, sizeof(nm_addr));
    if(ret < 0) {
        printf("connect 失败\n");
        close(nm_sock);
        close(sock);
        return (void*)-1;
    }
    //此时已经链接到NodeMCU

    do{
        memset(line, 0, sizeof(line));
        getlin(sock, line);
        //每获得一行，就像nodeMCU中写入
        //write(nm_sock, line, strlen(line));
        printf("%s",line);
    } while(line[0] != '\n');

    printf("循环退出\n");
    write(nm_sock, "\r\n", 2);

    close(nm_sock);
    close(sock);
    return NULL;
}

int main()
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0) {
        perror("socket");
        return 1;
    }
    startup(sock);

    printf("HTTP 服务器启动成功!\n");

    while(1) {
        struct sockaddr_in client_socket;
        socklen_t len = 0;

        //accept()
        //本函数从s的等待连接队列中抽取第一个连接，创建一个与s同类的新的套接口并返回句柄。\
        //如果队列中无等待连接，且套接口为阻塞方式，则accept()阻塞调用进程直至新的连接出现。
        //如果套接口为非阻塞方式且队列中无等待连接，则accept()返回一错误代码。
        //已接受连接的套接口不能用于接受新的连接，原套接口仍保持开放
        int client_sock = accept(sock, (struct sockaddr*)&client_socket, &len);
        if(client_sock < 0) {
            perror("accept");
            continue;
        }

        //以下证明accept已经获得了一个新的套接字,创建一个线程去处理
        pthread_t tid = 0;

        pthread_create(&tid, NULL, server, (void*)&client_sock);
        pthread_detach(tid);
    }
    return 0;
}
